/*
 * Delegate.h
 *
 *  Created on: May 19, 2013
 *      Author: Lucifer
 */

#ifndef __DELEGATE_H__
#define __DELEGATE_H__

#include <new>	// for replacement new.
#include "TypeTraits.h"
#include "Bind.h"

namespace BFX
{

/**
 * This class represents a delegate, which is a data structure that refers to a static method or to a class instance
 * and an instance method of that class.
 */
template<typename Signature>
class Delegate;

namespace _PRIV
{

////////////////////////////////////////////////////////////////////////////////
// Base types.

/*
 * A buffer used to store delegate function pointers or functor objects.
 * It is a union containing function pointers, functor objects.
 */
union DelegateBuffer
{
	mutable void (*m_pfn)();		// For function pointers of all kinds
	mutable char m_data[64];		// For functor objects
};

/*
 * Tags used to decide between different types of factors.
 */
struct DelegateFunctionPointerTag
{
};
struct DelegateFunctorObjectTag
{
};
struct DelegateMemberPointerTag
{
};

/*
 * Uses to decide type of given functor parameter.
 *
 */
template<typename F>
struct DelegateTagResolver
{
	typedef typename mpl::if_c<(tt::is_pointer<F>::value), DelegateFunctionPointerTag, DelegateFunctorObjectTag>::type PTR_OR_OBJ_TAG;

	typedef typename mpl::if_c<(tt::is_member_pointer<F>::value), DelegateMemberPointerTag, PTR_OR_OBJ_TAG>::type PTR_OR_OBJ_OR_MEM_TAG;

	// NOTE: we have not yet support stl reference wrapper.

public:
	typedef PTR_OR_OBJ_OR_MEM_TAG TYPE;
};

/*
 * The operation type to perform on the given functor.
 */
enum FanctorManagerOp
{
	CloneFunctorTag,
	ExchangeFunctorTag,
	DestroyFunctorTag,
};

/*
 * This class contains a static function "Invoke" which can clone or destroy the given function
 * pointer/object.
 */
template<typename Functor>
struct FanctorManager
{
	// Manages delegate buffer.
	static void Invoke(const DelegateBuffer& bufferIn, DelegateBuffer& bufferOut, FanctorManagerOp op)
	{
		typedef typename DelegateTagResolver<Functor>::TYPE TAG_TYPE;
		Invoke(bufferIn, bufferOut, op, TAG_TYPE());
	}

private:
	// Special case of function pointer.
	static void Invoke(const DelegateBuffer& bufferIn, DelegateBuffer& bufferOut, FanctorManagerOp op,
			DelegateFunctionPointerTag)
	{
		if (op == CloneFunctorTag)
		{
			bufferOut.m_pfn = bufferIn.m_pfn;
		}
		else if (op == ExchangeFunctorTag)
		{
            bufferOut.m_pfn = bufferIn.m_pfn;
            bufferIn.m_pfn = 0;
		}
		else if (op == DestroyFunctorTag)
		{
			bufferOut.m_pfn = 0;
		}
	}
	// Special case for object.
	static void Invoke(const DelegateBuffer& bufferIn, DelegateBuffer& bufferOut, FanctorManagerOp op,
			DelegateFunctorObjectTag)
	{
		if (op == CloneFunctorTag || op == ExchangeFunctorTag)
		{
			const Functor* functorIn = reinterpret_cast<const Functor*>(&bufferIn.m_data);
			new (reinterpret_cast<void*>(&bufferOut.m_data)) Functor(*functorIn);
		}
		else if (op == DestroyFunctorTag)
		{
			reinterpret_cast<Functor*>(&bufferOut.m_data)->~Functor();
			bufferOut.m_pfn = 0;
		}
	}
};

/*
 * This class stores the "manager" portion of the vtable for a Delegate object.
 */
struct VTableBase
{
	void (*m_pfnManage)(const DelegateBuffer& bufferIn, DelegateBuffer& bufferOut, FanctorManagerOp op);
};

/*
 * This class contains the basic elements needed for the Delegate. It is common to all delegates.
 */
struct DelegateBase
{
	DelegateBase() :
			m_pVTable(0)
	{
	}

	bool IsEmpty() const
	{
		return m_pVTable == 0;
	}

	VTableBase* m_pVTable;
	mutable DelegateBuffer m_functor;
};

}	//	namespace _PRIV

////////////////////////////////////////////////////////////////////////////////
// T0 templates.

namespace _PRIV
{

/**
 * This class represents a delegate, which is a data structure that refers to a static method or to a class instance
 * and an instance method of that class.
 * This specialization equivalent to R Delegate().
 */
template<typename R>
struct VTableT0
{
	typedef R RESULT_TYPE;
	typedef RESULT_TYPE (*INVOKER_TYPE)(DelegateBuffer&);

	template<typename F>
	bool Assign(F f, DelegateBuffer& functor) const
	{
		typedef typename DelegateTagResolver<F>::TYPE TAG;
		return Assign(f, functor, TAG());
	}
	void Clear(DelegateBuffer& functor) const
	{
		if (m_base.m_pfnManage != 0)
			m_base.m_pfnManage(functor, functor, DestroyFunctorTag);
	}
private:
	template<typename FunctionPtr>
	bool Assign(FunctionPtr f, DelegateBuffer& functor, DelegateFunctionPointerTag) const
	{
		Clear(functor);
		if (f != 0)
		{
			functor.m_pfn = reinterpret_cast<void (*)()>(f);
			return true;
		}
		return false;
	}
	template<typename FunctionObj>
	bool Assign(FunctionObj f, DelegateBuffer& functor, DelegateFunctorObjectTag) const
	{
		// Clear(functor);
		// NOTE: we need to check 'f' first to prevent use a invalid functor type.
		if (sizeof(FunctionObj) <= sizeof(DelegateBuffer))
		{
			new (reinterpret_cast<void*>(&functor.m_data)) FunctionObj(f);
			return true;
		}
		return false;
	}

public:
	VTableBase m_base;
	INVOKER_TYPE m_invoker;
};

/*
 * Represents a invoker that used a function pointer.
 */
template<typename FunctionPtr, typename R>
struct DelegateFunctionPointerInvokerT0
{
	static R Invoke(DelegateBuffer& functionPtr)
	{
		FunctionPtr f = reinterpret_cast<FunctionPtr>(functionPtr.m_pfn);
		return f();
	}
};

/*
 * Represents a invoker that used a functor object.
 */
template<typename FunctionObj, typename R>
struct DelegateFunctorObjectInvokerT0
{
	static R Invoke(DelegateBuffer& functionPtr)
	{
		FunctionObj* f;
		f = reinterpret_cast<FunctionObj*>(functionPtr.m_data);
		return (*f)();
	}
};

/*
 * To decide which type of invoker we are uses for.
 */
template<typename Tag>
struct DelegateInvokerResolverT0
{
};
template<>
struct DelegateInvokerResolverT0<DelegateFunctionPointerTag>
{
	template<typename FunctionPtr, typename R>
	struct Apply
	{
		typedef DelegateFunctionPointerInvokerT0<FunctionPtr, R> INVOKER_TYPE;
		typedef FanctorManager<FunctionPtr> MANAGER_TYPE;
	};
};
template<>
struct DelegateInvokerResolverT0<DelegateFunctorObjectTag>
{
	template<typename FunctionObj, typename R>
	struct Apply
	{
		typedef DelegateFunctorObjectInvokerT0<FunctionObj, R> INVOKER_TYPE;
		typedef FanctorManager<FunctionObj> MANAGER_TYPE;
	};
};

/*
 * Represents a delegate that refers to a method with no parameter.
 */
template<typename R>
class DelegateT0: public DelegateBase
{
public:
	typedef R RESULT_TYPE;

	DelegateT0() :
			DelegateBase()
	{
	}
	template<typename Functor>
	DelegateT0(Functor f) :
			DelegateBase()
	{
		Assign(f);
	}
	DelegateT0(const DelegateT0& f) :
			DelegateBase()
	{
		AssignClone(f);
	}
	~DelegateT0()
	{
		Clear();
	}
	RESULT_TYPE operator()() const
	{
		if (IsEmpty())
			return RESULT_TYPE();

		return GetVTable()->m_invoker(m_functor);
	}
	template<typename Functor>
	DelegateT0& operator=(Functor f)
	{
		Clear();
		Assign(f);

		return *this;
	}
	DelegateT0& operator=(const DelegateT0& f)
	{
		if (&f == this)
			return *this;
		Clear();
		AssignClone(f);

		return *this;
	}
	void Swap(DelegateT0& other)
	{
      if (&other == this)
        return;

      DelegateT0 t;
      t.AssignSwap(*this);
      AssignSwap(other);
      other.AssignSwap(t);
	}
	void Clear()
	{
		if (m_pVTable != 0)
		{
			GetVTable()->Clear(m_functor);
			m_pVTable = 0;
		}
	}

private:
	typedef VTableT0<R> VTABLE_TYPE;
	VTABLE_TYPE* GetVTable() const
	{
		return reinterpret_cast<VTABLE_TYPE*>(m_pVTable);
	}
	void AssignClone(const DelegateT0& f)
	{
		if (!f.IsEmpty())
		{
			m_pVTable = f.m_pVTable;
			GetVTable()->m_base.m_pfnManage(f.m_functor, m_functor, CloneFunctorTag);
		}
	}
	template<typename Functor>
	void Assign(Functor f)
	{
		typedef typename DelegateTagResolver<Functor>::TYPE TAG;
		typedef DelegateInvokerResolverT0<TAG> INVOKER_RESOLVER_TYPE;
		typedef typename INVOKER_RESOLVER_TYPE::template Apply<Functor, R> HANDLER_TYPE;

		typedef typename HANDLER_TYPE::INVOKER_TYPE INVOKER_TYPE;
		typedef typename HANDLER_TYPE::MANAGER_TYPE MANAGER_TYPE;

		static VTABLE_TYPE s_vtable = { { MANAGER_TYPE::Invoke }, INVOKER_TYPE::Invoke };

		if (s_vtable.Assign(f, m_functor))
		{
			size_t address = reinterpret_cast<size_t>(&s_vtable.m_base);
			m_pVTable = reinterpret_cast<VTableBase*>(address);
		}
		else
			m_pVTable = 0;
	}

	void AssignSwap(DelegateT0& f)
	{
      if (&f == this)
        return;

	  if (!f.IsEmpty())
	  {
		  m_pVTable = f.m_pVTable;
		  GetVTable()->m_base.m_pfnManage(f.m_functor, m_functor, ExchangeFunctorTag);
		  f.m_pVTable = 0;
	  }
	  else
		  Clear();
	}
};

}	//	namespace _PRIV

/**
 * This class represents a delegate, which is a data structure that refers to a static method or to a class instance
 * and an instance method of that class.
 * This specialization equivalent to R Delegate().
 */
template<typename R>
class Delegate<R(void)> : public _PRIV::DelegateT0<R>
{
	typedef _PRIV::DelegateT0<R> BASE_TYPE;
public:
	Delegate() :
			BASE_TYPE()
	{
	}
	template<typename Functor>
	Delegate(Functor f) :
			BASE_TYPE(f)
	{
	}
	Delegate(const Delegate& f) :
			BASE_TYPE(static_cast<const BASE_TYPE&>(f))
	{
	}
	Delegate(const BASE_TYPE& f) :
			BASE_TYPE(f)
	{
	}
	Delegate& operator=(const Delegate& f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
	Delegate& operator=(const BASE_TYPE& f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
	template<typename Functor>
	Delegate& operator=(Functor f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
};

////////////////////////////////////////////////////////////////////////////////
// T1 templates.
namespace _PRIV
{

template<typename R, typename T0>
struct VTableT1
{
	typedef R RESULT_TYPE;
	typedef RESULT_TYPE (*INVOKER_TYPE)(DelegateBuffer&, T0);

	template<typename F>
	bool Assign(F f, DelegateBuffer& functor) const
	{
		typedef typename DelegateTagResolver<F>::TYPE TAG;
		return Assign(f, functor, TAG());
	}
	void Clear(DelegateBuffer& functor) const
	{
		if (m_base.m_pfnManage != 0)
			m_base.m_pfnManage(functor, functor, DestroyFunctorTag);
	}
private:
	template<typename FunctionPtr>
	bool Assign(FunctionPtr f, DelegateBuffer& functor, DelegateFunctionPointerTag) const
	{
		Clear(functor);
		if (f != 0)
		{
			functor.m_pfn = reinterpret_cast<void (*)()>(f);
			return true;
		}
		return false;
	}
	template<typename FunctionObj>
	bool Assign(FunctionObj f, DelegateBuffer& functor, DelegateFunctorObjectTag) const
	{
		// Clear(functor);
		// NOTE: we need to check 'f' first to prevent use a invalid functor type.
		if (sizeof(FunctionObj) <= sizeof(DelegateBuffer))
		{
			new (reinterpret_cast<void*>(&functor.m_data)) FunctionObj(f);
			return true;
		}
		return false;
	}

public:
	VTableBase m_base;
	INVOKER_TYPE m_invoker;
};

template<typename FunctionPtr, typename R, typename T0>
struct DelegateFunctionPointerInvokerT1
{
	static R Invoke(DelegateBuffer& functionPtr, T0 t0)
	{
		FunctionPtr f = reinterpret_cast<FunctionPtr>(functionPtr.m_pfn);
		return f(t0);
	}
};

template<typename FunctionObj, typename R, typename T0>
struct DelegateFunctorObjectInvokerT1
{
	static R Invoke(DelegateBuffer& functionPtr, T0 t0)
	{
		FunctionObj* f;
		f = reinterpret_cast<FunctionObj*>(functionPtr.m_data);
		return (*f)(t0);
	}
};

template<typename Tag>
struct DelegateInvokerResolverT1
{
};
template<>
struct DelegateInvokerResolverT1<DelegateFunctionPointerTag>
{
	template<typename FunctionPtr, typename R, typename T0>
	struct Apply
	{
		typedef DelegateFunctionPointerInvokerT1<FunctionPtr, R, T0> INVOKER_TYPE;
		typedef FanctorManager<FunctionPtr> MANAGER_TYPE;
	};
};
template<>
struct DelegateInvokerResolverT1<DelegateFunctorObjectTag>
{
	template<typename FunctionObj, typename R, typename T0>
	struct Apply
	{
		typedef DelegateFunctorObjectInvokerT1<FunctionObj, R, T0> INVOKER_TYPE;
		typedef FanctorManager<FunctionObj> MANAGER_TYPE;
	};
};

/*
 * Represents a delegate that refers to a method with 1 parameter.
 */
template<typename R, typename T0>
class DelegateT1: public DelegateBase
{
public:
	typedef R RESULT_TYPE;

	DelegateT1() :
			DelegateBase()
	{
	}
	template<typename Functor>
	DelegateT1(Functor f) :
			DelegateBase()
	{
		Assign(f);
	}
	DelegateT1(const DelegateT1& f) :
			DelegateBase()
	{
		AssignClone(f);
	}
	~DelegateT1()
	{
		Clear();
	}
	RESULT_TYPE operator()(T0 t0) const
	{
		if (IsEmpty())
			return RESULT_TYPE();

		return GetVTable()->m_invoker(m_functor, t0);
	}
	template<typename Functor>
	DelegateT1& operator=(Functor f)
	{
		Clear();
		Assign(f);

		return *this;
	}
	DelegateT1& operator=(const DelegateT1& f)
	{
		if (&f == this)
			return *this;
		Clear();
		AssignClone(f);

		return *this;
	}
	void Swap(DelegateT1& other)
	{
      if (&other == this)
        return;

      DelegateT1 t;
      t.AssignSwap(*this);
      AssignSwap(other);
      other.AssignSwap(t);
	}
	void Clear()
	{
		if (m_pVTable != 0)
		{
			GetVTable()->Clear(m_functor);
			m_pVTable = 0;
		}
	}

private:
	typedef VTableT1<R, T0> VTABLE_TYPE;
	VTABLE_TYPE* GetVTable() const
	{
		return reinterpret_cast<VTABLE_TYPE*>(m_pVTable);
	}
	void AssignClone(const DelegateT1& f)
	{
		if (!f.IsEmpty())
		{
			m_pVTable = f.m_pVTable;
			GetVTable()->m_base.m_pfnManage(f.m_functor, m_functor, CloneFunctorTag);
		}
	}
	template<typename Functor>
	void Assign(Functor f)
	{
		typedef typename DelegateTagResolver<Functor>::TYPE TAG;
		typedef DelegateInvokerResolverT1<TAG> INVOKER_RESOLVER_TYPE;
		typedef typename INVOKER_RESOLVER_TYPE::template Apply<Functor, R, T0> HANDLER_TYPE;

		typedef typename HANDLER_TYPE::INVOKER_TYPE INVOKER_TYPE;
		typedef typename HANDLER_TYPE::MANAGER_TYPE MANAGER_TYPE;

		static VTABLE_TYPE s_vtable = { { MANAGER_TYPE::Invoke }, INVOKER_TYPE::Invoke };

		if (s_vtable.Assign(f, m_functor))
		{
			size_t address = reinterpret_cast<size_t>(&s_vtable.m_base);
			m_pVTable = reinterpret_cast<VTableBase*>(address);
		}
		else
			m_pVTable = 0;
	}

	void AssignSwap(DelegateT1& f)
	{
      if (&f == this)
        return;

	  if (!f.IsEmpty())
	  {
		  m_pVTable = f.m_pVTable;
		  GetVTable()->m_base.m_pfnManage(f.m_functor, m_functor, ExchangeFunctorTag);
		  f.m_pVTable = 0;
	  }
	  else
		  Clear();
	}
};

}	//	namespace _PRIV

/**
 * This class represents a delegate, which is a data structure that refers to a static method or to a class instance
 * and an instance method of that class.
 * This specialization equivalent to R Delegate(T0).
 */
template<typename R, typename T0>
class Delegate<R(T0)> : public _PRIV::DelegateT1<R, T0>
{
	typedef _PRIV::DelegateT1<R, T0> BASE_TYPE;
public:
	Delegate() :
			BASE_TYPE()
	{
	}
	template<typename Functor>
	Delegate(Functor f) :
			BASE_TYPE(f)
	{
	}
	Delegate(const Delegate& f) :
			BASE_TYPE(static_cast<const BASE_TYPE&>(f))
	{
	}
	Delegate(const BASE_TYPE& f) :
			BASE_TYPE(f)
	{
	}
	Delegate& operator=(const Delegate& f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
	Delegate& operator=(const BASE_TYPE& f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
	template<typename Functor>
	Delegate& operator=(Functor f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
};

////////////////////////////////////////////////////////////////////////////////
// T2 templates.
namespace _PRIV
{

template<typename R, typename T0, typename T1>
struct VTableT2
{
	typedef R RESULT_TYPE;
	typedef RESULT_TYPE (*INVOKER_TYPE)(DelegateBuffer&, T0, T1);

	template<typename F>
	bool Assign(F f, DelegateBuffer& functor) const
	{
		typedef typename DelegateTagResolver<F>::TYPE TAG;
		return Assign(f, functor, TAG());
	}
	void Clear(DelegateBuffer& functor) const
	{
		if (m_base.m_pfnManage != 0)
			m_base.m_pfnManage(functor, functor, DestroyFunctorTag);
	}
private:
	template<typename FunctionPtr>
	bool Assign(FunctionPtr f, DelegateBuffer& functor, DelegateFunctionPointerTag) const
	{
		Clear(functor);
		if (f != 0)
		{
			functor.m_pfn = reinterpret_cast<void (*)()>(f);
			return true;
		}
		return false;
	}
	template<typename FunctionObj>
	bool Assign(FunctionObj f, DelegateBuffer& functor, DelegateFunctorObjectTag) const
	{
		// Clear(functor);
		// NOTE: we need to check 'f' first to prevent use a invalid functor type.
		if (sizeof(FunctionObj) <= sizeof(DelegateBuffer))
		{
			new (reinterpret_cast<void*>(&functor.m_data)) FunctionObj(f);
			return true;
		}
		return false;
	}

public:
	VTableBase m_base;
	INVOKER_TYPE m_invoker;
};

template<typename FunctionPtr, typename R, typename T0, typename T1>
struct DelegateFunctionPointerInvokerT2
{
	static R Invoke(DelegateBuffer& functionPtr, T0 t0, T1 t1)
	{
		FunctionPtr f = reinterpret_cast<FunctionPtr>(functionPtr.m_pfn);
		return f(t0, t1);
	}
};

template<typename FunctionObj, typename R, typename T0, typename T1>
struct DelegateFunctorObjectInvokerT2
{
	static R Invoke(DelegateBuffer& functionPtr, T0 t0, T1 t1)
	{
		FunctionObj* f;
		f = reinterpret_cast<FunctionObj*>(functionPtr.m_data);
		return (*f)(t0, t1);
	}
};

template<typename Tag>
struct DelegateInvokerResolverT2
{
};
template<>
struct DelegateInvokerResolverT2<DelegateFunctionPointerTag>
{
	template<typename FunctionPtr, typename R, typename T0, typename T1>
	struct Apply
	{
		typedef DelegateFunctionPointerInvokerT2<FunctionPtr, R, T0, T1> INVOKER_TYPE;
		typedef FanctorManager<FunctionPtr> MANAGER_TYPE;
	};
};
template<>
struct DelegateInvokerResolverT2<DelegateFunctorObjectTag>
{
	template<typename FunctionObj, typename R, typename T0, typename T1>
	struct Apply
	{
		typedef DelegateFunctorObjectInvokerT2<FunctionObj, R, T0, T1> INVOKER_TYPE;
		typedef FanctorManager<FunctionObj> MANAGER_TYPE;
	};
};

/*
 * Represents a delegate that refers to a method with 2 parameters.
 */
template<typename R, typename T0, typename T1>
class DelegateT2: public DelegateBase
{
public:
	typedef R RESULT_TYPE;

	DelegateT2() :
			DelegateBase()
	{
	}
	template<typename Functor>
	DelegateT2(Functor f) :
			DelegateBase()
	{
		Assign(f);
	}
	DelegateT2(const DelegateT2& f) :
			DelegateBase()
	{
		AssignClone(f);
	}
	~DelegateT2()
	{
		Clear();
	}
	RESULT_TYPE operator()(T0 t0, T1 t1) const
	{
		if (IsEmpty())
			return RESULT_TYPE();

		return GetVTable()->m_invoker(m_functor, t0, t1);
	}
	template<typename Functor>
	DelegateT2& operator=(Functor f)
	{
		Clear();
		Assign(f);

		return *this;
	}
	DelegateT2& operator=(const DelegateT2& f)
	{
		if (&f == this)
			return *this;
		Clear();
		AssignClone(f);

		return *this;
	}
	void Swap(DelegateT2& other)
	{
      if (&other == this)
        return;

      DelegateT2 t;
      t.AssignSwap(*this);
      AssignSwap(other);
      other.AssignSwap(t);
	}
	void Clear()
	{
		if (m_pVTable != 0)
		{
			GetVTable()->Clear(m_functor);
			m_pVTable = 0;
		}
	}

private:
	typedef VTableT2<R, T0, T1> VTABLE_TYPE;
	VTABLE_TYPE* GetVTable() const
	{
		return reinterpret_cast<VTABLE_TYPE*>(m_pVTable);
	}
	void AssignClone(const DelegateT2& f)
	{
		if (!f.IsEmpty())
		{
			m_pVTable = f.m_pVTable;
			GetVTable()->m_base.m_pfnManage(f.m_functor, m_functor, CloneFunctorTag);
		}
	}
	template<typename Functor>
	void Assign(Functor f)
	{
		typedef typename DelegateTagResolver<Functor>::TYPE TAG;
		typedef DelegateInvokerResolverT2<TAG> INVOKER_RESOLVER_TYPE;
		typedef typename INVOKER_RESOLVER_TYPE::template Apply<Functor, R, T0, T1> HANDLER_TYPE;

		typedef typename HANDLER_TYPE::INVOKER_TYPE INVOKER_TYPE;
		typedef typename HANDLER_TYPE::MANAGER_TYPE MANAGER_TYPE;

		static VTABLE_TYPE s_vtable = { { MANAGER_TYPE::Invoke }, INVOKER_TYPE::Invoke };

		if (s_vtable.Assign(f, m_functor))
		{
			size_t address = reinterpret_cast<size_t>(&s_vtable.m_base);
			m_pVTable = reinterpret_cast<VTableBase*>(address);
		}
		else
			m_pVTable = 0;
	}

	void AssignSwap(DelegateT2& f)
	{
      if (&f == this)
        return;

	  if (!f.IsEmpty())
	  {
		  m_pVTable = f.m_pVTable;
		  GetVTable()->m_base.m_pfnManage(f.m_functor, m_functor, ExchangeFunctorTag);
		  f.m_pVTable = 0;
	  }
	  else
		  Clear();
	}
};

}	//	namespace _PRIV

/**
 * This class represents a delegate, which is a data structure that refers to a static method or to a class instance
 * and an instance method of that class.
 * This specialization equivalent to R Delegate(T0, T1).
 */
template<typename R, typename T0, typename T1>
class Delegate<R(T0, T1)> : public _PRIV::DelegateT2<R, T0, T1>
{
	typedef _PRIV::DelegateT2<R, T0, T1> BASE_TYPE;
public:
	Delegate() :
			BASE_TYPE()
	{
	}
	template<typename Functor>
	Delegate(Functor f) :
			BASE_TYPE(f)
	{
	}
	Delegate(const Delegate& f) :
			BASE_TYPE(static_cast<const BASE_TYPE&>(f))
	{
	}
	Delegate(const BASE_TYPE& f) :
			BASE_TYPE(f)
	{
	}
	Delegate& operator=(const Delegate& f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
	Delegate& operator=(const BASE_TYPE& f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
	template<typename Functor>
	Delegate& operator=(Functor f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
};

////////////////////////////////////////////////////////////////////////////////
// T3 templates.

namespace _PRIV
{

template<typename R, typename T0, typename T1, typename T2>
struct VTableT3
{
	typedef R RESULT_TYPE;
	typedef RESULT_TYPE (*INVOKER_TYPE)(DelegateBuffer&, T0, T1, T2);

	template<typename F>
	bool Assign(F f, DelegateBuffer& functor) const
	{
		typedef typename DelegateTagResolver<F>::TYPE TAG;
		return Assign(f, functor, TAG());
	}
	void Clear(DelegateBuffer& functor) const
	{
		if (m_base.m_pfnManage != 0)
			m_base.m_pfnManage(functor, functor, DestroyFunctorTag);
	}
private:
	template<typename FunctionPtr>
	bool Assign(FunctionPtr f, DelegateBuffer& functor, DelegateFunctionPointerTag) const
	{
		Clear(functor);
		if (f != 0)
		{
			functor.m_pfn = reinterpret_cast<void (*)()>(f);
			return true;
		}
		return false;
	}
	template<typename FunctionObj>
	bool Assign(FunctionObj f, DelegateBuffer& functor, DelegateFunctorObjectTag) const
	{
		// Clear(functor);
		// NOTE: we need to check 'f' first to prevent use a invalid functor type.
		if (sizeof(FunctionObj) <= sizeof(DelegateBuffer))
		{
			new (reinterpret_cast<void*>(&functor.m_data)) FunctionObj(f);
			return true;
		}
		return false;
	}

public:
	VTableBase m_base;
	INVOKER_TYPE m_invoker;
};

template<typename FunctionPtr, typename R, typename T0, typename T1, typename T2>
struct DelegateFunctionPointerInvokerT3
{
	static R Invoke(DelegateBuffer& functionPtr, T0 t0, T1 t1, T2 t2)
	{
		FunctionPtr f = reinterpret_cast<FunctionPtr>(functionPtr.m_pfn);
		return f(t0, t1, t2);
	}
};

template<typename FunctionObj, typename R, typename T0, typename T1, typename T2>
struct DelegateFunctorObjectInvokerT3
{
	static R Invoke(DelegateBuffer& functionPtr, T0 t0, T1 t1, T2 t2)
	{
		FunctionObj* f;
		f = reinterpret_cast<FunctionObj*>(functionPtr.m_data);
		return (*f)(t0, t1, t2);
	}
};

template<typename Tag>
struct DelegateInvokerResolverT3
{
};
template<>
struct DelegateInvokerResolverT3<DelegateFunctionPointerTag>
{
	template<typename FunctionPtr, typename R, typename T0, typename T1, typename T2>
	struct Apply
	{
		typedef DelegateFunctionPointerInvokerT3<FunctionPtr, R, T0, T1, T2> INVOKER_TYPE;
		typedef FanctorManager<FunctionPtr> MANAGER_TYPE;
	};
};
template<>
struct DelegateInvokerResolverT3<DelegateFunctorObjectTag>
{
	template<typename FunctionObj, typename R, typename T0, typename T1, typename T2>
	struct Apply
	{
		typedef DelegateFunctorObjectInvokerT3<FunctionObj, R, T0, T1, T2> INVOKER_TYPE;
		typedef FanctorManager<FunctionObj> MANAGER_TYPE;
	};
};

/*
 * Represents a delegate that refers to a method with 3 parameters.
 */
template<typename R, typename T0, typename T1, typename T2>
class DelegateT3: public DelegateBase
{
public:
	typedef R RESULT_TYPE;

	DelegateT3() :
			DelegateBase()
	{
	}
	template<typename Functor>
	DelegateT3(Functor f) :
			DelegateBase()
	{
		Assign(f);
	}
	DelegateT3(const DelegateT3& f) :
			DelegateBase()
	{
		AssignClone(f);
	}
	~DelegateT3()
	{
		Clear();
	}
	RESULT_TYPE operator()(T0 t0, T1 t1, T2 t2) const
	{
		if (IsEmpty())
			return RESULT_TYPE();

		return GetVTable()->m_invoker(m_functor, t0, t1, t2);
	}
	template<typename Functor>
	DelegateT3& operator=(Functor f)
	{
		Clear();
		Assign(f);

		return *this;
	}
	DelegateT3& operator=(const DelegateT3& f)
	{
		if (&f == this)
			return *this;
		Clear();
		AssignClone(f);

		return *this;
	}
	void Swap(DelegateT3& other)
	{
      if (&other == this)
        return;

      DelegateT3 t;
      t.AssignSwap(*this);
      AssignSwap(other);
      other.AssignSwap(t);
	}
	void Clear()
	{
		if (m_pVTable != 0)
		{
			GetVTable()->Clear(m_functor);
			m_pVTable = 0;
		}
	}

private:
	typedef VTableT3<R, T0, T1, T2> VTABLE_TYPE;
	VTABLE_TYPE* GetVTable() const
	{
		return reinterpret_cast<VTABLE_TYPE*>(m_pVTable);
	}
	void AssignClone(const DelegateT3& f)
	{
		if (!f.IsEmpty())
		{
			m_pVTable = f.m_pVTable;
			GetVTable()->m_base.m_pfnManage(f.m_functor, m_functor, CloneFunctorTag);
		}
	}
	template<typename Functor>
	void Assign(Functor f)
	{
		typedef typename DelegateTagResolver<Functor>::TYPE TAG;
		typedef DelegateInvokerResolverT3<TAG> INVOKER_RESOLVER_TYPE;
		typedef typename INVOKER_RESOLVER_TYPE::template Apply<Functor, R, T0, T1, T2> HANDLER_TYPE;

		typedef typename HANDLER_TYPE::INVOKER_TYPE INVOKER_TYPE;
		typedef typename HANDLER_TYPE::MANAGER_TYPE MANAGER_TYPE;

		static VTABLE_TYPE s_vtable = { { MANAGER_TYPE::Invoke }, INVOKER_TYPE::Invoke };

		if (s_vtable.Assign(f, m_functor))
		{
			size_t address = reinterpret_cast<size_t>(&s_vtable.m_base);
			m_pVTable = reinterpret_cast<VTableBase*>(address);
		}
		else
			m_pVTable = 0;
	}

	void AssignSwap(DelegateT3& f)
	{
      if (&f == this)
        return;

	  if (!f.IsEmpty())
	  {
		  m_pVTable = f.m_pVTable;
		  GetVTable()->m_base.m_pfnManage(f.m_functor, m_functor, ExchangeFunctorTag);
		  f.m_pVTable = 0;
	  }
	  else
		  Clear();
	}
};

}	//	namespace _PRIV

/**
 * This class represents a delegate, which is a data structure that refers to a static method or to a class instance
 * and an instance method of that class.
 * This specialization equivalent to R Delegate(T0, T1, T2).
 */
template<typename R, typename T0, typename T1, typename T2>
class Delegate<R(T0, T1, T2)> : public _PRIV::DelegateT3<R, T0, T1, T2>
{
	typedef _PRIV::DelegateT3<R, T0, T1, T2> BASE_TYPE;
public:
	Delegate() :
			BASE_TYPE()
	{
	}
	template<typename Functor>
	Delegate(Functor f) :
			BASE_TYPE(f)
	{
	}
	Delegate(const Delegate& f) :
			BASE_TYPE(static_cast<const BASE_TYPE&>(f))
	{
	}
	Delegate(const BASE_TYPE& f) :
			BASE_TYPE(f)
	{
	}
	Delegate& operator=(const Delegate& f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
	Delegate& operator=(const BASE_TYPE& f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
	template<typename Functor>
	Delegate& operator=(Functor f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
};

////////////////////////////////////////////////////////////////////////////////
// T4 templates.

namespace _PRIV
{

template<typename R, typename T0, typename T1, typename T2, typename T3>
struct VTableT4
{
	typedef R RESULT_TYPE;
	typedef RESULT_TYPE (*INVOKER_TYPE)(DelegateBuffer&, T0, T1, T2, T3);

	template<typename F>
	bool Assign(F f, DelegateBuffer& functor) const
	{
		typedef typename DelegateTagResolver<F>::TYPE TAG;
		return Assign(f, functor, TAG());
	}
	void Clear(DelegateBuffer& functor) const
	{
		if (m_base.m_pfnManage != 0)
			m_base.m_pfnManage(functor, functor, DestroyFunctorTag);
	}
private:
	template<typename FunctionPtr>
	bool Assign(FunctionPtr f, DelegateBuffer& functor, DelegateFunctionPointerTag) const
	{
		Clear(functor);
		if (f != 0)
		{
			functor.m_pfn = reinterpret_cast<void (*)()>(f);
			return true;
		}
		return false;
	}
	template<typename FunctionObj>
	bool Assign(FunctionObj f, DelegateBuffer& functor, DelegateFunctorObjectTag) const
	{
		// Clear(functor);
		// NOTE: we need to check 'f' first to prevent use a invalid functor type.
		if (sizeof(FunctionObj) <= sizeof(DelegateBuffer))
		{
			new (reinterpret_cast<void*>(&functor.m_data)) FunctionObj(f);
			return true;
		}
		return false;
	}

public:
	VTableBase m_base;
	INVOKER_TYPE m_invoker;
};

template<typename FunctionPtr, typename R, typename T0, typename T1, typename T2, typename T3>
struct DelegateFunctionPointerInvokerT4
{
	static R Invoke(DelegateBuffer& functionPtr, T0 t0, T1 t1, T2 t2, T3 t3)
	{
		FunctionPtr f = reinterpret_cast<FunctionPtr>(functionPtr.m_pfn);
		return f(t0, t1, t2, t3);
	}
};

template<typename FunctionObj, typename R, typename T0, typename T1, typename T2, typename T3>
struct DelegateFunctorObjectInvokerT4
{
	static R Invoke(DelegateBuffer& functionPtr, T0 t0, T1 t1, T2 t2, T3 t3)
	{
		FunctionObj* f;
		f = reinterpret_cast<FunctionObj*>(functionPtr.m_data);
		return (*f)(t0, t1, t2, t3);
	}
};

template<typename Tag>
struct DelegateInvokerResolverT4
{
};
template<>
struct DelegateInvokerResolverT4<DelegateFunctionPointerTag>
{
	template<typename FunctionPtr, typename R, typename T0, typename T1, typename T2, typename T3>
	struct Apply
	{
		typedef DelegateFunctionPointerInvokerT4<FunctionPtr, R, T0, T1, T2, T3> INVOKER_TYPE;
		typedef FanctorManager<FunctionPtr> MANAGER_TYPE;
	};
};
template<>
struct DelegateInvokerResolverT4<DelegateFunctorObjectTag>
{
	template<typename FunctionObj, typename R, typename T0, typename T1, typename T2, typename T3>
	struct Apply
	{
		typedef DelegateFunctorObjectInvokerT4<FunctionObj, R, T0, T1, T2, T3> INVOKER_TYPE;
		typedef FanctorManager<FunctionObj> MANAGER_TYPE;
	};
};

/*
 * Represents a delegate that refers to a method with 4 parameters.
 */
template<typename R, typename T0, typename T1, typename T2, typename T3>
class DelegateT4: public DelegateBase
{
public:
	typedef R RESULT_TYPE;

	DelegateT4() :
			DelegateBase()
	{
	}
	template<typename Functor>
	DelegateT4(Functor f) :
			DelegateBase()
	{
		Assign(f);
	}
	DelegateT4(const DelegateT4& f) :
			DelegateBase()
	{
		AssignClone(f);
	}
	~DelegateT4()
	{
		Clear();
	}
	RESULT_TYPE operator()(T0 t0, T1 t1, T2 t2, T3 t3) const
	{
		if (IsEmpty())
			return RESULT_TYPE();

		return GetVTable()->m_invoker(m_functor, t0, t1, t2, t3);
	}
	template<typename Functor>
	DelegateT4& operator=(Functor f)
	{
		Clear();
		Assign(f);

		return *this;
	}
	DelegateT4& operator=(const DelegateT4& f)
	{
		if (&f == this)
			return *this;
		Clear();
		AssignClone(f);

		return *this;
	}
	void Swap(DelegateT4& other)
	{
      if (&other == this)
        return;

      DelegateT4 t;
      t.AssignSwap(*this);
      AssignSwap(other);
      other.AssignSwap(t);
	}
	void Clear()
	{
		if (m_pVTable != 0)
		{
			GetVTable()->Clear(m_functor);
			m_pVTable = 0;
		}
	}

private:
	typedef VTableT4<R, T0, T1, T2, T3> VTABLE_TYPE;
	VTABLE_TYPE* GetVTable() const
	{
		return reinterpret_cast<VTABLE_TYPE*>(m_pVTable);
	}
	void AssignClone(const DelegateT4& f)
	{
		if (!f.IsEmpty())
		{
			m_pVTable = f.m_pVTable;
			GetVTable()->m_base.m_pfnManage(f.m_functor, m_functor, CloneFunctorTag);
		}
	}
	template<typename Functor>
	void Assign(Functor f)
	{
		typedef typename DelegateTagResolver<Functor>::TYPE TAG;
		typedef DelegateInvokerResolverT4<TAG> INVOKER_RESOLVER_TYPE;
		typedef typename INVOKER_RESOLVER_TYPE::template Apply<Functor, R, T0, T1, T2, T3> HANDLER_TYPE;

		typedef typename HANDLER_TYPE::INVOKER_TYPE INVOKER_TYPE;
		typedef typename HANDLER_TYPE::MANAGER_TYPE MANAGER_TYPE;

		static VTABLE_TYPE s_vtable = { { MANAGER_TYPE::Invoke }, INVOKER_TYPE::Invoke };

		if (s_vtable.Assign(f, m_functor))
		{
			size_t address = reinterpret_cast<size_t>(&s_vtable.m_base);
			m_pVTable = reinterpret_cast<VTableBase*>(address);
		}
		else
			m_pVTable = 0;
	}

	void AssignSwap(DelegateT4& f)
	{
      if (&f == this)
        return;

	  if (!f.IsEmpty())
	  {
		  m_pVTable = f.m_pVTable;
		  GetVTable()->m_base.m_pfnManage(f.m_functor, m_functor, ExchangeFunctorTag);
		  f.m_pVTable = 0;
	  }
	  else
		  Clear();
	}
};

}	//	namespace _PRIV

/**
 * This class represents a delegate, which is a data structure that refers to a static method or to a class instance
 * and an instance method of that class.
 * This specialization equivalent to R Delegate(T0, T1, T2, T3).
 */
template<typename R, typename T0, typename T1, typename T2, typename T3>
class Delegate<R(T0, T1, T2, T3)> : public _PRIV::DelegateT4<R, T0, T1, T2, T3>
{
	typedef _PRIV::DelegateT4<R, T0, T1, T2, T3> BASE_TYPE;
public:
	Delegate() :
			BASE_TYPE()
	{
	}
	template<typename Functor>
	Delegate(Functor f) :
			BASE_TYPE(f)
	{
	}
	Delegate(const Delegate& f) :
			BASE_TYPE(static_cast<const BASE_TYPE&>(f))
	{
	}
	Delegate(const BASE_TYPE& f) :
			BASE_TYPE(f)
	{
	}
	Delegate& operator=(const Delegate& f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
	Delegate& operator=(const BASE_TYPE& f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
	template<typename Functor>
	Delegate& operator=(Functor f)
	{
		Delegate(f).Swap(*this);
		return *this;
	}
};

}	//	namespace BFX

#endif /* __DELEGATE_H__ */
